package com.dt.app.security.handler;

import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.dt.app.api.sys.service.SysLoginLogService;
import com.dt.app.common.constant.ConstantCode;
import com.dt.app.common.response.ResultEnum;
import com.dt.app.common.response.ResultUtil;
import com.dt.app.common.utils.CmsMenuTreeUtils;
import com.dt.app.common.utils.IpAddressUtils;
import com.dt.app.common.utils.ServletUtils;
import com.dt.app.modules.base.entites.PayloadEntity;
import com.dt.app.modules.sys.entities.SysPermissionEntity;
import com.dt.app.modules.sys.entities.SysUserEntity;
import com.dt.app.modules.sys.vo.response.SysMenuResponse;
import com.dt.app.security.rsa.RsaJwtUtils;
import lombok.SneakyThrows;
import lombok.extern.apachecommons.CommonsLog;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 登录认证成功处理器
 * @author DT
 * @date 2021/6/5 10:31
 */
@CommonsLog
@Component
public class LoginSuccessHandler implements AuthenticationSuccessHandler {

    private final RsaJwtUtils rsaJwtUtils;
    private final SysLoginLogService sysLoginLogService;

    public LoginSuccessHandler(RsaJwtUtils rsaJwtUtils, SysLoginLogService sysLoginLogService) {
        this.rsaJwtUtils = rsaJwtUtils;
        this.sysLoginLogService = sysLoginLogService;
    }

    @SneakyThrows
    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) {
        // 1.生成token
        SysUserEntity user = (SysUserEntity)authentication.getPrincipal();
        PayloadEntity payloadEntity = rsaJwtUtils.getDefaultPayload(user.getUsername());
        String token = rsaJwtUtils.generateTokenByRsa(JSONUtil.toJsonStr(payloadEntity),rsaJwtUtils.getDefaultRsaKey());
        SysMenuResponse menuResponse = new SysMenuResponse();
        menuResponse.setToken(token);
        menuResponse.setUserId(user.getId());
        menuResponse.setAccountName(user.getAccountName());
        // 2.获取用户菜单权限
        List<SysPermissionEntity> permissionList = user.getPermissionList();
        // 3.获取按钮权限
        List<String> auth = permissionList.stream().filter(Objects::nonNull).map(SysPermissionEntity::getCode).collect(Collectors.toList());
        menuResponse.setAuthList(auth);
        // 4.生成菜单数据树
        List<SysPermissionEntity> permissions = permissionList.stream().filter(item -> item != null && !"2".equals(item.getType())).collect(Collectors.toList());
        List<SysPermissionEntity> listMenu = CmsMenuTreeUtils.makeTree(permissions, 0L);
        menuResponse.setMenuList(listMenu);
        // 5.查询路由的url
        List<SysPermissionEntity> routerList = permissionList.stream().filter(item -> item != null && "1".equals(item.getType())).collect(Collectors.toList());
        menuResponse.setRouterList(routerList);
        // 6.记录登录日志
        String ip = IpAddressUtils.getIpAddr(ServletUtils.getRequest());
        UserAgent userAgent = UserAgentUtil.parse(httpServletRequest.getHeader("User-Agent"));
        this.sysLoginLogService.saveLoginLog(ConstantCode.LOGIN_STRING_KEY, user.getUsername(),userAgent,ip);
        String res = JSONObject.toJSONString(ResultUtil.success(ResultEnum.SUCCESS,ResultEnum.SUCCESS_MESSAGE,menuResponse), SerializerFeature.DisableCircularReferenceDetect);
        httpServletResponse.setContentType("application/json;charset=UTF-8");
        ServletOutputStream out = httpServletResponse.getOutputStream();
        out.write(res.getBytes(StandardCharsets.UTF_8));
        out.flush();
        out.close();
    }

}
